﻿using System.Globalization;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows;

namespace FrontDisplay.Controls
{
    /// <summary>
    /// OutlineText custom control class derives layout, event, data binding, and rendering from derived FrameworkElement class.
    /// </summary>
    public class OutlineTextBlock : FrameworkElement
    {
        #region Private Fields

        //private Geometry _textGeometry;
        private Geometry _textHighLightGeometry;

        #endregion

        #region Private Methods

        /// <summary>
        /// Invoked when a dependency property has changed. Generate a new FormattedText object to display.
        /// </summary>
        /// <param name="d">OutlineText object whose property was updated.</param>
        /// <param name="e">Event arguments for the dependency property.</param>
        private static void OnOutlineTextInvalidated(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((OutlineTextBlock)d).CreateText();
        }

        #endregion

        #region FrameworkElement Overrides
        /// <summary>
        /// OnRender override draws the geometry of the text and optional highlight.
        /// </summary>
        /// <param name="drawingContext">Drawing context of the OutlineText control.</param>
        protected override void OnRender(DrawingContext drawingContext)
        {
            ////Draw the outline based on the properties that are set.
            //drawingContext.DrawGeometry(Foreground, new Pen(Stroke, StrokeThickness), _textGeometry);

            FormattedText formattedText = new FormattedText(
                Text,
                CultureInfo.GetCultureInfo("en-us"),
                FlowDirection.LeftToRight,
                new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
                FontSize,
                Stroke);

            drawingContext.DrawText(formattedText, new Point(0, 0));
            drawingContext.DrawText(formattedText, new Point(0, 2));
            drawingContext.DrawText(formattedText, new Point(2, 0));
            drawingContext.DrawText(formattedText, new Point(2, 2));

            formattedText.SetForegroundBrush(Foreground);

            drawingContext.DrawText(formattedText, new Point(1, 1));

            // Draw the text highlight based on the properties that are set.
            //if (Highlight)
            //{
            //    drawingContext.DrawGeometry(null, new Pen(Stroke, StrokeThickness), _textHighLightGeometry);
            //}
        }
        /// <summary>
        /// Create the outline geometry based on the formatted text.
        /// </summary>
        public void CreateText()
        {
            // Create the formatted text based on the properties set.
            FormattedText formattedText = new FormattedText(
                Text,
                CultureInfo.GetCultureInfo("en-us"),
                FlowDirection.LeftToRight,
                new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
                FontSize,
                Brushes.Black // This brush does not matter since we use the geometry of the text. 
                );

            //// Build the geometry object that represents the text.
            //_textGeometry = formattedText.BuildGeometry(new Point(0, 0));

            // Build the geometry object that represents the text hightlight.
            //if (Highlight)
            {
                _textHighLightGeometry = formattedText.BuildHighlightGeometry(new Point(0, 0));
            }
            Width = Size.Width;
        }
        #endregion

        #region DependencyProperties

        public FontStyle FontStyle
        {
            get { return (FontStyle) GetValue(FontStyleProperty); }
            set { SetValue(FontStyleProperty, value); }
        }

        public static readonly DependencyProperty FontStyleProperty = DependencyProperty.Register(
            "FontStyle",
            typeof(FontStyle),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(FontStyles.Normal, FrameworkPropertyMetadataOptions.AffectsRender, OnOutlineTextInvalidated, null));

        public FontWeight FontWeight
        {
            get { return (FontWeight)GetValue(FontWeightProperty); }
            set { SetValue(FontWeightProperty, value); }
        }

        public static readonly DependencyProperty FontWeightProperty = DependencyProperty.Register(
            "FontWeight",
            typeof(FontWeight),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(FontWeights.Normal, FrameworkPropertyMetadataOptions.AffectsRender, OnOutlineTextInvalidated, null));

        public FontStretch FontStretch
        {
            get { return (FontStretch)GetValue(FontStretchProperty); }
            set { SetValue(FontStretchProperty, value); }
        }

        public static readonly DependencyProperty FontStretchProperty = DependencyProperty.Register(
            "FontStretch",
            typeof(FontStretch),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(FontStretches.Normal, FrameworkPropertyMetadataOptions.AffectsRender, OnOutlineTextInvalidated, null));

        ///// <summary>
        ///// Specifies the brush to use for the fill of the formatted text.
        ///// </summary>
        //public Brush Fill
        //{
        //    get { return (Brush)GetValue(FillProperty); }
        //    set { SetValue(FillProperty, value); }
        //}

        ///// <summary>
        ///// Identifies the Fill dependency property.
        ///// </summary>
        //public static readonly DependencyProperty FillProperty = DependencyProperty.Register(
        //    "Fill",
        //    typeof(Brush),
        //    typeof(OutlineTextBlock),
        //    new FrameworkPropertyMetadata(new SolidColorBrush(Colors.Black), FrameworkPropertyMetadataOptions.AffectsRender, OnOutlineTextInvalidated, null));

        public FontFamily FontFamily
        {
            get { return (FontFamily)GetValue(FontFamilyProperty); }
            set { SetValue(FontFamilyProperty, value); }
        }

        /// <summary>
        /// Identifies the Font dependency property.
        /// </summary>
        public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.Register(
            "FontFamily",
            typeof(FontFamily),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(new FontFamily("Tahoma"), FrameworkPropertyMetadataOptions.AffectsRender, OnOutlineTextInvalidated, null));

        /// <summary>
        /// The current font size.
        /// </summary>
        public double FontSize
        {
            get { return (double)GetValue(FontSizeProperty);} 
            set { SetValue(FontSizeProperty, value); }
        }

        /// <summary>
        /// Identifies the FontSize dependency property.
        /// </summary>
        public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
            "FontSize",
            typeof(double),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(48.0, FrameworkPropertyMetadataOptions.AffectsRender, OnOutlineTextInvalidated, null));

        ///// <summary>
        ///// Specifies whether to show the text highlight.
        ///// </summary>
        //public bool Highlight
        //{
        //    get { return (bool)GetValue(HighlightProperty); }
        //    set { SetValue(HighlightProperty, value); }
        //}

        ///// <summary>
        ///// Identifies the Hightlight dependency property.
        ///// </summary>
        //public static readonly DependencyProperty HighlightProperty = DependencyProperty.Register(
        //    "Highlight",
        //    typeof(bool),
        //    typeof(OutlineTextBlock),
        //    new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender, OnOutlineTextInvalidated, null));

        /// <summary>
        /// Specifies the brush to use for the stroke and optional hightlight of the formatted text.
        /// </summary>
        public Brush Stroke
        {
            get { return (Brush)GetValue(StrokeProperty); }
            set { SetValue(StrokeProperty, value); }
        }

        /// <summary>
        /// Identifies the Stroke dependency property.
        /// </summary>
        public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
            "Stroke",
            typeof(Brush),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(new SolidColorBrush(Colors.Gray), FrameworkPropertyMetadataOptions.AffectsRender, OnOutlineTextInvalidated, null));

        /// <summary>
        /// The stroke thickness of the font.
        /// </summary>
        public ushort StrokeThickness
        {
            get { return (ushort)GetValue(StrokeThicknessProperty); }
            set { SetValue(StrokeThicknessProperty, value); }
        }

        /// <summary>
        /// Identifies the StrokeThickness dependency property.
        /// </summary>
        public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
            "StrokeThickness",
            typeof(ushort),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata((ushort)1, FrameworkPropertyMetadataOptions.AffectsRender, OnOutlineTextInvalidated, null));

        /// <summary>
        /// Specifies the text string to display.
        /// </summary>
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value ?? string.Empty); }
        }

        /// <summary>
        /// Identifies the Text dependency property.
        /// </summary>
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
            "Text",
            typeof(string),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsRender, OnOutlineTextInvalidated, null));

        public Brush Foreground
        {
            get { return (Brush)GetValue(Control.ForegroundProperty); }
            set { SetValue(Control.ForegroundProperty, value); }
        }

        public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
            "Foreground",
            typeof(Brush),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(new SolidColorBrush(Colors.Black), FrameworkPropertyMetadataOptions.AffectsRender, OnOutlineTextInvalidated, null));

        public Thickness Padding
        {
            get { return (Thickness)GetValue(PaddingProperty); }
            set { SetValue(PaddingProperty, value); }
        }

        public static readonly DependencyProperty PaddingProperty = DependencyProperty.Register(
            "Padding",
            typeof(Thickness),
            typeof(OutlineTextBlock),
            new FrameworkPropertyMetadata(new Thickness(0), FrameworkPropertyMetadataOptions.AffectsRender, OnOutlineTextInvalidated, null));

        #endregion

        protected override Size MeasureOverride(Size availableSize)
        {
            InvalidateVisual();
            return Size;
        }

        public Size Size
        {
            get
            {
                if (_textHighLightGeometry != null) return _textHighLightGeometry.Bounds.Size;
                return new Size();
            }
        }
    }
}
